/**
 * 微信支付v2版本
 * 请勿修改此处代码，因为插件更新后此处代码会被覆盖。
 * 作者：VK
 * 发布于：2021-07-06
 */
const fs = require("fs");
const crypto = require("crypto");
const libs = require('../../libs');

class VkWxPayV2 {

	constructor(config) {

		let {
			appId,
			secret,
			mchId, // 商户id
			key, // v2密钥
			pfx, // 证书（支持base64或Buffer）
			apiUrl = "https://api.mch.weixin.qq.com", // 微信网关API
		} = config;

		this.config = {
			appId,
			secret,
			mchId,
			key,
			pfx,
			apiUrl
		};
	}
	/**
	 * 获取请求的xml（MD5加密方式）
	 * @param {Object} params 参数
	 */
	getXMLForMD5(params) {
		let config = this.config;
		let signParams = JSON.parse(JSON.stringify(params));
		let str = this.getSignStr(signParams) + '&key=' + config.key;
		let sign = this.signForMD5(str);
		signParams.sign = sign;
		let xmlStr = this.buildXML(signParams);
		return xmlStr;
	}
	/**
	 * 获取请求的xml（hmacsha256加密方式）
	 * @param {Object} params 参数
	 */
	getXMLForHmacsha256(params, needAppid) {
		let config = this.config;
		let signParams;
		if (needAppid) {
			signParams = Object.assign({
				appid: config.appId,
				mch_id: config.mchId
			}, params);
		} else {
			signParams = Object.assign({
				mch_id: config.mchId
			}, params);
		}

		signParams = JSON.parse(JSON.stringify(signParams));
		const str = this.getSignStr(signParams) + '&key=' + config.key;
		let sign = this.signForHmacsha256(str, config, "utf8").toUpperCase();
		signParams.sign = sign;
		let xmlStr = this.buildXML(signParams);
		return xmlStr;
	}

	/**
	 * 获取待签名的字符串
	 * @param {Object} obj 待签名的参数
	 */
	getSignStr(obj) {
		return Object.keys(obj)
			.filter(key => key !== 'sign' && obj[key] !== undefined && obj[key] !== '')
			.sort()
			.map(key => key + '=' + obj[key])
			.join('&')
	}
	/**
	 * md5签名
	 */
	signForMD5(str, encoding = 'utf8') {
		return crypto.createHash('md5').update(str, encoding).digest('hex').toUpperCase();
	}
	/**
	 * hmacsha256签名
	 */
	signForHmacsha256(str, encoding = 'utf8') {
		let config = this.config;
		// 生成签名
		let cryptostr = crypto.createHmac('sha256', config.key).update(str, encoding).digest('hex');
		return cryptostr;
	}


	/**
	 * 简易版Object转XML，只可在微信支付时使用，不支持嵌套
	 */
	buildXML(obj, rootName = 'xml') {
		const content = Object.keys(obj).map(item => {
			if (Object.prototype.toString.call(obj[item]) === '[object Object]') {
				return `<${item}><![CDATA[${JSON.stringify(obj[item])}]]></${item}>`
			} else {
				return `<${item}><![CDATA[${obj[item]}]]></${item}>`
			}
		})
		return `<${rootName}>${content.join('')}</${rootName}>`
	}

	/**
	 * 发起请求
	 */
	async request(obj = {}) {
		let config = this.config;
		let {
			method,
			url,
			data = {},
			needCert,
			needAppid = true,
			signType = "md5",
			dataType = "text",
			successText
		} = obj;
		method = method.toUpperCase(); // 转大写
		signType = signType.toLowerCase(); // 转小写
		// 生成随机字符串
		if (!data.nonce_str) data.nonce_str = libs.common.random(32);
		// 计算签名
		let xmlStr = "";
		if (signType === "md5") {
			xmlStr = this.getXMLForMD5(data);
		} else if (signType === "hmacsha256") {
			xmlStr = this.getXMLForHmacsha256(data, needAppid);
		}
		let apiUrl = config.apiUrl;
		let requestOptions = {
			url: apiUrl + url,
			method,
			dataType,
			data: xmlStr
		}
		if (needCert) {
			requestOptions.pfx = config.pfx;
			requestOptions.passphrase = config.mchId;
		}
		let res = { code: 0, msg: "" };
		// 发起http请求
		let resultXMLStr = await libs.common.request(requestOptions);
		let result = libs.common.parseXML(resultXMLStr);
		if (result.result_code !== "SUCCESS") {
			res.code = result.err_code || result.return_code || result.error_code;
			res.msg = result.err_code_des || result.return_msg || result.error_msg;
		} else {
			res.msg = successText;
		}
		res.result = result;
		return res;
	};

	/**
	 * 企业转账到零钱
	 */
	async transfer(obj = {}) {
		let {
			partner_trade_no,
			openid,
			check_name,
			re_user_name,
			amount,
			desc,
			appid = this.config.appId,
			mchid = this.config.mchId,
		} = obj;

		let res = await this.request({
			method: "POST",
			url: `/mmpaymkttransfers/promotion/transfers`,
			data: {
				partner_trade_no,
				openid,
				check_name,
				re_user_name,
				amount,
				desc,
				mch_appid: appid,
				mchid
			},
			needCert: true,
			signType: "md5",
			dataType: "text",
			successText: "转账成功"
		});

		return res;
	}

}

module.exports = VkWxPayV2;
